package de.zainodis.commons.model.binding;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import de.zainodis.commons.utils.StringUtils;

/**
 * A datapath wraps a String path to an object's attribute. For an Object Car
 * with the attribute Name - the datapath would be Car/Name.
 * 
 * @author zainodis
 */
public final class Datapath implements IDatapath {

   /** An empty default datapath. */
   public static final IDatapath EMPTY = new Datapath(StringUtils.EMPTY);

   /** Represents the actual path, i.e. Car/Owner/Name */
   private final String path;

   @Override
   public boolean contains(String value) {
	 return path.contains(value);
   }

   /**
    * Creates a new {@link Datapath}. If the given path is null, it is
    * automatically converted to {@link Datapath#EMPTY}.
    * 
    * @param path
    *           a {@link String} representing the path of this datapath.
    */
   public Datapath(String path) {
	 if (path == null) {
	    path = StringUtils.EMPTY;
	 }
	 this.path = path;
   }

   public Collection<IDatapath> split() {
	 Collection<IDatapath> result = new ArrayList<IDatapath>();
	 String[] pathNodes = path.split(PATH_SEPARATOR);

	 for (String current : pathNodes) {
	    result.add(new Datapath(current));
	 }
	 return result;
   }

   @Override
   public Iterator<IDatapath> iterator() {
	 return split().iterator();
   }

   /**
    * Combines two datapaths by using a defined separator.
    * 
    * @param left
    *           this datapath marks the beginning of the newly created datapath
    * @param right
    *           this datapath will be appended to the left datapath
    * @return a {@link Datapath}, which is a combination of both provided
    *         datapaths
    * @throws IllegalArgumentException
    *            if either of the provided arguments is null
    */
   public static Datapath combine(String left, String right) {
	 if (left != null && right != null) {
	    return new Datapath(left + PATH_SEPARATOR + right);
	 }
	 String errorMessage = "Neither of the datapaths that are to be combined may be null";
	 throw new IllegalArgumentException(errorMessage);
   }

   @Override
   public String getLastPart() {
	 IDatapath[] parts = split().toArray(new IDatapath[0]);
	 return parts[parts.length - 1].toString();
   }

   @Override
   public boolean startsWith(String prefix) {
	 return path.startsWith(prefix);
   }

   @Override
   public String toString() {
	 return path;
   }

   @Override
   public boolean equals(Object o) {
	 if (o != null) {
	    if (o instanceof IDatapath) {
		  if (this.toString().equals(o.toString())) {
			return true;
		  }
	    }
	 }
	 return false;
   }

   @Override
   public boolean isEmpty() {
	 return equals(EMPTY);
   }

   @Override
   public int getLength() {
	 return split().size();
   }
}
